package com.ctshk.rpc.guide.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ctshk.common.dto.Result;
import com.ctshk.common.enums.*;
import com.ctshk.common.model.PageResponse;
import com.ctshk.common.model.TokenUser;
import com.ctshk.common.utils.EntityUtil;
import com.ctshk.common.utils.SnowflakeIdWorker;
import com.ctshk.rpc.guide.dto.GuideCollarQueryLeisureDTO;
import com.ctshk.rpc.guide.dto.GuideCollarSchedulingDTO;
import com.ctshk.rpc.guide.dto.TeaPartyDTO;
import com.ctshk.rpc.guide.dto.TeaPartyHost;
import com.ctshk.rpc.guide.entity.GuideCollar;
import com.ctshk.rpc.guide.entity.GuideCollarScheduling;
import com.ctshk.rpc.guide.entity.TeaParty;
import com.ctshk.rpc.guide.mapper.GuideCollarMapper;
import com.ctshk.rpc.guide.mapper.GuideCollarSchedulingMapper;
import com.ctshk.rpc.guide.mapper.TeaPartyMapper;
import com.ctshk.rpc.guide.req.*;
import com.ctshk.rpc.guide.service.ITeaPartyService;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Period;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 茶会管理表 服务实现类
 * </p>
 *
 * @author 谢诗宏
 * @since 2021-03-03
 */
@DubboService
public class TeaPartyServiceImpl extends ServiceImpl<TeaPartyMapper, TeaParty> implements ITeaPartyService {

    @Autowired
    private GuideCollarSchedulingMapper guideCollarSchedulingMapper;
    @Autowired
    private GuideCollarSchedulingServiceImpl guideCollarSchedulingService;
    @Autowired
    private GroupDistributionServiceImpl groupDistributionService;
    @Autowired
    private GuideCollarMapper guideCollarMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result add(TeaPartyAddReq req, TokenUser tokenUser) {
        QueryWrapper<TeaParty> qw = new QueryWrapper<>();
        qw.lambda().eq(TeaParty::getGroupId, req.getGroupId())
                .eq(TeaParty::getIsDeleted, IsDeletedCode.NO.getCode());
        Integer integer = baseMapper.selectCount(qw);
        if (integer > 0) {
            return Result.failed(SystemError.GUIDE_41009);
        }
        TeaParty teaParty = EntityUtil.copy(req, TeaParty.class);
        long id = SnowflakeIdWorker.nextId();
        LocalDateTime now = LocalDateTime.now();
        teaParty.setId(id);
        teaParty.setIsDeleted(IsDeletedCode.NO.getCode());
        teaParty.setModifiedId(tokenUser.getId());
        teaParty.setCreateId(tokenUser.getId());
        teaParty.setGmtCreate(now);
        teaParty.setGmtModified(now);
        int insert = baseMapper.insert(teaParty);
        if (insert > 0) {
            //这个地方貌似不会用到。。。哎写都写了。。好像还要判断空闲。。。
            if (teaParty.getTeaPartyHost() != null && teaParty.getTeaPartyHost().size() > 0) {
                for (TeaPartyHost tph : teaParty.getTeaPartyHost()) {
                    if (teaParty.getTeaPartyTime().getHour() < 12) {//上午的茶会
                        addGuideCollarScheduling(teaParty.getTeaPartyTime().toLocalDate(),
                                teaParty.getTeaPartyTime().toLocalDate(),
                                tph.getId(), tph.getUserName()
                                , GuideCollarSchedulingType.DATE.getCode(),
                                GuideCollarSchedulingWorkHours.FORENOON.getCode(),
                                GuideCollarSchedulingServiceImpl.WORKID3,
                                GuideCollarSchedulingServiceImpl.WORKID3_NAME, tokenUser, teaParty.getId());
                    } else {//下午的茶会
                        addGuideCollarScheduling(teaParty.getTeaPartyTime().toLocalDate(),
                                teaParty.getTeaPartyTime().toLocalDate(),
                                tph.getId(), tph.getUserName()
                                , GuideCollarSchedulingType.DATE.getCode(),
                                GuideCollarSchedulingWorkHours.AFTERNOON.getCode(),
                                GuideCollarSchedulingServiceImpl.WORKID3,
                                GuideCollarSchedulingServiceImpl.WORKID3_NAME, tokenUser, teaParty.getId());
                    }
                }
            }
            return Result.success(id);
        }
        return Result.failed(SystemError.SYS_437);
    }

    private void addGuideCollarScheduling(LocalDate begin, LocalDate end, Long guideCollarId,
                                          String guideCollarName, Integer type, Integer hours
            , Long workTypeId, String workTypeName, TokenUser tu, Long groupId) {
        GuideCollarSchedulingAddReq gcslareq = new GuideCollarSchedulingAddReq();
        gcslareq.setSchedulingDateBegin(begin);//安排开始日期
        gcslareq.setSchedulingDateEnd(end);//安排终止日期
        gcslareq.setGuideCollarId(guideCollarId);//导领ID
        gcslareq.setGuideCollarName(guideCollarName);//导领名称
        gcslareq.setArrangementType(type);//安排类型
        gcslareq.setWorkingHours(hours);//工作时段
        gcslareq.setWorkTypeId(workTypeId);//工作类型id
        gcslareq.setWorkTypeName(workTypeName);//工作类型name
        gcslareq.setGroupId(groupId);//这个位置是茶会ID
        guideCollarSchedulingService.add(gcslareq, tu,false);
    }

    @Override
    public TeaPartyDTO query(TeaPartyIdReq req) {
        TeaParty teaParty = baseMapper.selectById(req.getId());
        TeaPartyDTO teaPartyDTO = EntityUtil.copy(teaParty, TeaPartyDTO.class);
        return teaPartyDTO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result updateHost(TeaPartyHostUpdateReq req, TokenUser tokenUser) {
        TeaParty teaParty = EntityUtil.copy(req, TeaParty.class);
        //在修改茶会前查出记录用于删除原来主持人的工作安排
        TeaParty teaParty1 = baseMapper.selectById(req.getId());
        if (teaParty1 != null) {
            LocalDateTime teaPartyTime = teaParty1.getTeaPartyTime();//茶会时间
            List<TeaPartyHost> tphs = req.getTeaPartyHost();
            // 校监茶会主持人有无工作安排   如果要安排的茶会主持人的 原工作安排  就是当前这个茶会  就不需要判断跳过就行了
            if (tphs != null && tphs.size() > 0) {
                //判断导领有无合约到期
                for(TeaPartyHost e:tphs){
                    GuideCollar gc = guideCollarMapper.selectById(e.getId());
                    if(gc != null) {
                        int workDays = Period.between(gc.getEntryTime(), LocalDate.now()).getDays();
                        if (workDays > gc.getContractPeriod() * 365) {
                            return Result.failed(SystemError.GUIDE_410011);
                        }
                    }else{
                        return Result.failed(SystemError.GUIDE_41005);
                    }
                };
                GuideCollarQueryLeisureReq gcqlreq = new GuideCollarQueryLeisureReq();
                gcqlreq.setBeginDate(teaPartyTime);
                gcqlreq.setType(GuideCollarType.TEA_PARTY.getCode());
//                gcqlreq.setGroupType(1);//是否需要筛选领队或导游
                Result<List<GuideCollarQueryLeisureDTO>> select = groupDistributionService.select(gcqlreq);
                //这段时间和全天的所有的任务这些任务包含
                List<GuideCollarSchedulingDTO> task = groupDistributionService.getTask(gcqlreq);
                List<Long> userIds = null;
                if (task != null && task.size() > 0) {
                    //过滤这些任务取出和当前茶会有关系的任务
                    task = task.stream().filter(e -> e.getGroupId() == teaParty1.getId()).collect(Collectors.toList());
                    if (task != null && task.size() > 0) {
                        //得到为当前茶会服务的领队或导领IDS
                        userIds = task.stream().map(e -> e.getGuideCollarId()).collect(Collectors.toList());
                    }
                }
                List<GuideCollarQueryLeisureDTO> data = select.getData();
                if (data == null || data.size() < 1) {
                    return Result.failed(SystemError.GUIDE_41008);
                }
                //空闲的领队或导游
                Set<Long> collect1 = data.stream().map(e -> e.getId()).collect(Collectors.toSet());
                //想安排的领队或导游
                Set<Long> collect2 = tphs.stream().map(e -> e.getId()).collect(Collectors.toSet());
                for (Long item : collect2) {
                    //要安排的领队必须在空闲领队中出现 否则就失败
                    if (!collect1.contains(item)) {
                        //想安排的领队或导游原本就是服务这个茶会的不算
                        if (userIds != null && userIds.contains(item)) {
                            continue;
                        }
                        return Result.failed(SystemError.GUIDE_41008);
                    }
                }
            }
            LocalDateTime now = LocalDateTime.now();
            teaParty.setGmtModified(now);
            teaParty.setModifiedId(tokenUser.getId());
            int i = baseMapper.updateById(teaParty);
            if (i > 0) {
                List<TeaPartyHost> json = teaParty1.getTeaPartyHost();
                //在修改茶会主持人时需要将原来茶会主持人的排班修改（也有可能没有）
                if (json != null && json.size() > 0) {
                    String s = JSON.toJSONString(json);
                    JSONArray objects = JSONArray.parseArray(s);
                    List<TeaPartyHost> list = objects.toJavaList(TeaPartyHost.class);
                    Set<Long> collect = list.stream().map(e -> e.getId()).collect(Collectors.toSet());
                    //有主持人的时候要先删除工作安排在加给新的主持人工作安排
                    if (teaPartyTime.getHour() < 12) { //上午
                        QueryWrapper<GuideCollarScheduling> qw = new QueryWrapper();
                        qw.lambda().eq(GuideCollarScheduling::getSchedulingDate, teaPartyTime.toLocalDate())
                                .eq(GuideCollarScheduling::getWorkingHours, GuideCollarSchedulingWorkHours.FORENOON.getCode())//（只删除上午的）
                                .eq(GuideCollarScheduling::getGroupId, teaParty1.getId())//匹配是同一个茶会的工作安排
                                .in(GuideCollarScheduling::getGuideCollarId, collect);
                        guideCollarSchedulingMapper.delete(qw);
                    } else {//下午
                        QueryWrapper<GuideCollarScheduling> qw = new QueryWrapper();
                        qw.lambda().eq(GuideCollarScheduling::getSchedulingDate, teaPartyTime.toLocalDate())
                                .eq(GuideCollarScheduling::getWorkingHours, GuideCollarSchedulingWorkHours.AFTERNOON.getCode())//（只删除下午的）
                                .eq(GuideCollarScheduling::getGroupId, teaParty1.getId())//匹配是同一个茶会的工作安排
                                .in(GuideCollarScheduling::getGuideCollarId, collect);
                        guideCollarSchedulingMapper.delete(qw);
                    }
                }
                //在这里我们需要把新的茶会人添加进去
                if (req.getTeaPartyHost() != null && req.getTeaPartyHost().size() > 0) {
                    for (TeaPartyHost tph : req.getTeaPartyHost()) {
                        if (teaPartyTime.getHour() < 12) {//上午的茶会
                            addGuideCollarScheduling(teaPartyTime.toLocalDate(),
                                    teaPartyTime.toLocalDate(),
                                    tph.getId(), tph.getUserName()
                                    , GuideCollarSchedulingType.DATE.getCode(),
                                    GuideCollarSchedulingWorkHours.FORENOON.getCode(),
                                    GuideCollarSchedulingServiceImpl.WORKID3,
                                    GuideCollarSchedulingServiceImpl.WORKID3_NAME, tokenUser, teaParty1.getId());
                        } else {//下午的茶会
                            addGuideCollarScheduling(teaPartyTime.toLocalDate(),
                                    teaPartyTime.toLocalDate(),
                                    tph.getId(), tph.getUserName()
                                    , GuideCollarSchedulingType.DATE.getCode(),
                                    GuideCollarSchedulingWorkHours.AFTERNOON.getCode(),
                                    GuideCollarSchedulingServiceImpl.WORKID3,
                                    GuideCollarSchedulingServiceImpl.WORKID3_NAME, tokenUser, teaParty1.getId());
                        }
                    }
                }
            }
        }
        return Result.success(req.getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result updateGroupStatus(TeaPartyGroupStatusUpdateReq req, TokenUser tokenUser) {
        TeaParty teaParty = EntityUtil.copy(req, TeaParty.class);
        LocalDateTime now = LocalDateTime.now();
        long id = SnowflakeIdWorker.nextId();
        teaParty.setGmtModified(now);
        teaParty.setModifiedId(tokenUser.getId());
        baseMapper.updateById(teaParty);
        return Result.success(req.getId());
    }

    @Override
    public PageResponse<TeaPartyDTO> list(TeaPartyListReq req) {
        Page<TeaParty> page = new Page<>(req.getPageNo(), req.getPageSize());
        QueryWrapper<TeaParty> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(null != req.getGroupType(), TeaParty::getGroupType, req.getGroupType())
                .eq(null != req.getGroupStatus(), TeaParty::getGroupStatus, req.getGroupStatus())
                .eq(StringUtils.isNotBlank(req.getGroupNumber()), TeaParty::getGroupNumber, req.getGroupNumber())
                .eq(TeaParty::getIsDeleted, IsDeletedCode.NO.getCode())
                .ge(null != req.getDaysMin(), TeaParty::getDays, req.getDaysMin())
                .le(null != req.getDaysMax(), TeaParty::getDays, req.getDaysMax())
                .ge(null != req.getReceivedNumberMin(), TeaParty::getReceivedNumber, req.getReceivedNumberMin())
                .le(null != req.getReceivedNumberMax(), TeaParty::getReceivedNumber, req.getReceivedNumberMax());
        if (null != req.getTeaPartyTimeStart() && null != req.getTeaPartyTimeEnd()) {
            queryWrapper.lambda().between(TeaParty::getTeaPartyTime, req.getTeaPartyTimeStart(), req.getTeaPartyTimeEnd());
        }
        queryWrapper.lambda().orderByDesc(TeaParty::getGmtCreate);
        Page<TeaParty> iPage = baseMapper.selectPage(page, queryWrapper);
        List<TeaParty> records = iPage.getRecords();
        if (CollectionUtils.isEmpty(records)) {
            return new PageResponse<>(new ArrayList<>(), iPage.getCurrent() == 1, iPage.getTotal() <= (iPage.getCurrent() * iPage.getSize()), iPage.getTotal(), iPage.getCurrent(), iPage.getSize());
        }
        List<TeaPartyDTO> teaPartyDTOS = EntityUtil.copyList(records, TeaPartyDTO.class);
        return new PageResponse<>(teaPartyDTOS, iPage.getCurrent() == 1, iPage.getTotal() <= (iPage.getCurrent() * iPage.getSize()), iPage.getTotal(), iPage.getCurrent(), iPage.getSize());

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result delete(TeaPartyDeleteReq req, TokenUser tokenUser) {
        List<Long> ids = req.getIds();
        if (ids != null && ids.size() > 0) {
            int count = 0;
            for (Long id : ids) {
                //删除主持人应该先清空茶会主持人的工作记录
                TeaParty teaParty1 = baseMapper.selectById(id);
                if (teaParty1 != null) {
                    LocalDateTime now = LocalDateTime.now();
                    teaParty1.setGmtModified(now);
                    teaParty1.setTeaPartyHost(null);//删除茶会主持人
                    teaParty1.setModifiedId(tokenUser.getId());
                    count += baseMapper.updateById(teaParty1);
                }
            }
            if (count > 0) {
                QueryWrapper<GuideCollarScheduling> qw = new QueryWrapper();
                //直接删除关于这个茶会ID的所有工作安排
                qw.lambda().eq(GuideCollarScheduling::getIsDeleted, IsDeletedCode.NO.getCode())
                        .in(GuideCollarScheduling::getGroupId, ids);
                guideCollarSchedulingMapper.delete(qw);
            }
            return Result.success();
        }
        return Result.failed(SystemError.GUIDE_41006);
    }
}
